//
//  IMPlain.swift
//  ActorSDK
//
//  Created by 孙继刚 on 16/2/24.
//  Copyright © 2016年 Madordie. All rights reserved.
//

import UIKit

/// 全部类方法，暂时是对ActorSDK的一个嫁接，
public class IMPlain: NSObject {
    
    //
    // Shared instance
    //
    
    private static let shared =  IMPlain()
    
    public static func sharedActor() -> IMPlain {
        return shared
    }

    public let appDelegate = IMPlainAppDelegate()
    public let originalSDK = ActorSDK.sharedActor()
    
    
    /**
     配置
     
     - returns: 如果出错将反悔错误信息
     */
    public func configuration(endpoints: [String]) -> NSError? {
        
        let aactorSDK = ActorSDK.sharedActor()
        
        assert(endpoints.count > 0, "No set endpodints.")
        aactorSDK.endpoints = endpoints
        
        //  Default
        ActorSDK.sharedActor().inviteUrlHost = "quit.email"
        ActorSDK.sharedActor().inviteUrlScheme = "actor"
        
        ActorSDK.sharedActor().style.searchStatusBarStyle = .Default
        
        // Enabling experimental features
        ActorSDK.sharedActor().enableExperimentalFeatures = true
        
        // Setting Development Push Id
        ActorSDK.sharedActor().apiPushId = 868547
        
        return nil
    }
    /**
     创建
     */
    public func creatActor() {
        ActorSDK.sharedActor().createActor()
    }
    
    
    static var anyOne: AnyObject?
    
    static var messageCount = 0
    
    public func test() -> Bool {
        validateCommand(phone: "8617701873282", code: "iOSDEV", successBlock: { (authState) -> Void in
            let bindObj = ""
            let listener = self.chat(getDialogsDisplayListForBindObj: bindObj, changeNotifa: { (bindObj, displayList, ChangeType, fromIndexPaths, toIndexPaths) -> Void in
                let item = displayList.itemWithIndex(NSIndexPath(forRow: 0, inSection: 0))
                self.chat(messagePeer: item!["ACPeer"] as! ACPeer, text: "\(IMPlain.messageCount++)")
            })
            
            listener.startListen()
            IMPlain.anyOne = listener
            }) { (val) -> Void in
                print("\(val)")
        }
        
        
        return true
    }
    
    // MARK: - 验证操作
    
    /**
     验证验证码操作
        //  If logged in state: end authentication  ->  ACAuthState.LOGGED_IN().ordinal()
        //  Is signup go to signup controller       ->  ACAuthState.SIGN_UP().ordinal()
        //  If state not for the current state: start from scratch  ->  !ACAuthState.CODE_VALIDATION_PHONE().ordinal()
        //  If same state: something code is incorrect  -> else
     - parameter code:         验证码
     - parameter successBlock: 验证成功
     - parameter failureBlock: 验证失败
     */
    public func validateCommand(phone phone: String!, code: String!, successBlock: ((authState: jint!) -> Void)?, failureBlock: ((val: Any?) -> Void)?) {
        
        let command = Actor.requestStartAuthCommandWithPhone(phone.toJLong());
        
        print("\(command)")
        
        AAExecutions.execute(command, type: .Safe, ignore: [], successBlock: { (val) -> Void in
            let command = Actor.validateCodeCommand(code)
            
            AAExecutions.execute(command, type: .Safe, ignore: ["PHONE_CODE_INVALID"], successBlock: { (val) -> Void in
                
                let state = Actor.getAuthState().ordinal()
                successBlock?(authState: state)
                
                }, failureBlock: failureBlock)

            }, failureBlock: failureBlock)
    }
    
    /**
     验证密码操作
         //  If logged in state: end authentication  ->  ACAuthState.LOGGED_IN().ordinal()
         //  Is signup go to signup controller       ->  ACAuthState.SIGN_UP().ordinal()
         //  If state not for the current state: start from scratch  ->  !ACAuthState.CODE_VALIDATION_PHONE().ordinal()
         //  If same state: something code is incorrect  -> else
     - parameter pw:           密码
     - parameter successBlock: 验证成功
     - parameter failureBlock: 验证失败
     */
    public func validateCommand(passWord pw: String!, successBlock: ((authState: jint!) -> Void)?, failureBlock: ((val: Any?) -> Void)?) {
        let command = Actor.validatePasswordCommand(pw)
        AAExecutions.execute(command, type: .Safe, ignore: ["PHONE_CODE_INVALID"], successBlock: { (val) -> Void in
            
            let state = Actor.getAuthState().ordinal()
            successBlock?(authState: state)
            
            }, failureBlock: failureBlock)
    }
    
    // MARK: - 聊天相关
    
    /**
    消息聊天列表绑定 不需要额外的操作进行保存列表，直接获取即可。
    
    - parameter peer:         联系人
    - parameter bindObj:      绑定对象
    - parameter changeNotifa: 回调
    
    - returns: 绑定的观察者。请自行保存此对象。 count、item(->change)、
    */
    public func chat(getMessageDisplayListForPeer peer: ACPeer!, bindObj: AnyObject!, changeNotifa: (bindObj: AnyObject!, displayList: IMDisplayList, ChangeType: IMListChangeType!, fromIndexPaths: [NSIndexPath]?, toIndexPaths: [NSIndexPath]?) -> Void) -> IMDisplayList {
        let list = Actor.getMessageDisplayList(peer)
        let listener = IMDisplayList(bindObj: bindObj, displayList: list, changeNotifa: changeNotifa)
        listener.formatItem = {item -> [String: AnyObject] in
            if item is ACMessage {
                return (item as! ACDialog).formatToDictionary()
            }
            assert(false, "item 类型识别错误")
            return ["type is error": item]
        }
        listener.listenerType = IMDisplayList.ListenerType.Apple
        return listener
    }
    /**
     获取最近联系人列表
     
     - parameter bindObj:      绑定对象
     - parameter changeNotifa: 回调
     
     - returns: 绑定的观察者。请自行保存此对象。 count、item(->change)、
     */
    public func chat(getDialogsDisplayListForBindObj bindObj: AnyObject!, changeNotifa: (bindObj: AnyObject!, displayList: IMDisplayList, ChangeType: IMListChangeType!, fromIndexPaths: [NSIndexPath]?, toIndexPaths: [NSIndexPath]?) -> Void) -> IMDisplayList {
        let list = Actor.getDialogsDisplayList()
        let listener = IMDisplayList(bindObj: bindObj, displayList: list, changeNotifa: changeNotifa)
        listener.formatItem = {item -> [String: AnyObject] in
            if item is ACDialog {
                return (item as! ACDialog).formatToDictionary()
            }
            assert(false, "item 类型识别错误")
            return ["type is error": item]
        }
        listener.listenerType = IMDisplayList.ListenerType.Default
        return listener
    }
    /**
     获取通讯录列表
     
     - parameter bindObj:      绑定对象
     - parameter changeNotifa: 回调
     
     - returns: 绑定的观察者。请自行保存此对象。 count、item(->change)、
     */
    public func chat(buildContactsDisplayListForBindObj bindObj: AnyObject!, changeNotifa: (bindObj: AnyObject!, displayList: IMDisplayList, ChangeType: IMListChangeType!, fromIndexPaths: [NSIndexPath]?, toIndexPaths: [NSIndexPath]?) -> Void) -> IMDisplayList {
        let list = Actor.buildContactsDisplayList()
        let listener = IMDisplayList(bindObj: bindObj, displayList: list, changeNotifa: changeNotifa)
        listener.formatItem = {item -> [String: AnyObject] in
            if item is ACContact {
                return (item as! ACDialog).formatToDictionary()
            }
            assert(false, "item 类型识别错误")
            return ["type is error": item]
        }
        listener.listenerType = IMDisplayList.ListenerType.Default
        return listener
    }
    
    /**
    给peer发文本消息
    
    - parameter peer: peer
    - parameter text: 文本消息
    */
    public func chat(messagePeer peer: ACPeer!, text: String) {
        Actor.sendMessageWithMentionsDetect(peer, withText: text)
    }
    
    /**
     给peer发送图片
     
     - parameter peer:   peer
     - parameter images: 图片集合
     */
    public func chat(messagePeer peer: ACPeer!, images: [UIImage]?, completionHandler: ((Any?) -> Void)?) {
        guard let _ = images else { completionHandler?("images = nil"); return }
        guard images!.count == 0 else { completionHandler?("images.cout = 0"); return }

        //  参看SDK源码: ActorSDK/Sources/Controllers/Content/Conversation/Views/AttachmentView/AAConvActionSheet.swift:309# func sendPhotos()
        
        let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
        dispatch_async(dispatch_get_global_queue(priority, 0)) {
            
            for image in images! {
                Actor.sendUIImage(image, peer: peer)
            }
        
            guard completionHandler == nil else { return }
            dispatch_async(dispatch_get_main_queue()) {
                completionHandler!("应该是结束了,SDK 连个回调都没有😂")
            }
        }
    }
    /**
     给Peer发送音频消息
     
     - parameter peer:       peer
     - parameter audioName:  audioName  //  关于默认值我也不知道是个什么意思，SDK中这样写的。
     - parameter duration:   时间
     - parameter descriptor: descriptor
     */
    public func chat(messagePeer peer: ACPeer!, audioName: String = NSString.localizedStringWithFormat("%@.ogg", NSUUID().UUIDString) as String, duration: jint, descriptor: String) {
        Actor.sendAudioWithPeer(peer, withName: audioName, withDuration: duration, withDescriptor: descriptor)
    }
    // MARK: 手贱，把他的录音那块东西整出来万一外面的出问题用这个火补
    /**
    开始录音
        //  每次请根据需要传入delegate
    - parameter recorder: nil或已经创建的AAAudioRecorder对象
    - parameter delegate: 遵从AAAudioRecorderDelegate协议的对象。需测试是否可用。
    
    - returns: 新建的或者传入的AAAudioRecorder
    */
    public func recordVideo(recorderBegin rrecorder: AAAudioRecorder?, delegate: AAAudioRecorderDelegate?) -> AAAudioRecorder! {
        var recorder: AAAudioRecorder!
        if rrecorder == nil {
            recorder = AAAudioRecorder()
        } else {
            recorder = rrecorder!
        }
        recorder.delegate = delegate
        recorder.start()
        return recorder
    }
    /**
     结束录音
     
     - parameter recorder: 需要结束的句柄
     - parameter finished: 完成文件保存之后的信息
     */
    public func recordVideo(recorderFinished recorder: AAAudioRecorder!, finished:((descriptor: String, duration: jint) -> Void)!) {
        recorder.finish({ (path: String!, duration: NSTimeInterval) -> Void in
            
            if (nil == path) {
                print("onAudioRecordingFinished: empty path")
                return
            }
            
            NSLog("onAudioRecordingFinished: %@ [%lfs]", path, duration)
            let range = path.rangeOfString("/tmp", options: NSStringCompareOptions(), range: nil, locale: nil)
            let descriptor = path.substringFromIndex(range!.startIndex)
            NSLog("Audio Recording file: \(descriptor)")
            
            finished?(descriptor: descriptor, duration: jint(duration*1000))
        })
    }
    /**
     播放音频
        //  并不懂。源码：ActorSDK/Source/Controllers/Content/COnversation/AAConversationContentController.swift #370 func playVoiceFromPath(path:String,fileId:jlong,position:Float) 、 #410 func playVideoFromPath(path:String)
     - parameter pplayer:  播放器
     - parameter path:     路径
     - parameter fileID:   文件ID
     - parameter position: position description
     
     - returns: 最新播放器
     */
    public func playVideo(player pplayer: AAModernConversationAudioPlayer?, path: String!, fileID: jlong, position: Float) -> AAModernConversationAudioPlayer! {
        pplayer?.stop()
        pplayer?.audioPlayerStopAndFinish()
        
        let player = AAModernConversationAudioPlayer(filePath: path)
        player.play()
        
        return player
    }
    
    // MARK: - 个人信息
    
    /**
    修改个人头像、昵称
    
    - parameter name:         昵称
    - parameter avatar:       头像
    - parameter successBlock: 成功回调
    - parameter failureBlock: 失败回调
    */
    public func ownCommand(changeName name: String?, avatar: UIImage?, successBlock: ((val: Any?) -> Void)?, failureBlock: ((val: Any?) -> Void)?) {
        
        if avatar != nil {
            Actor.changeOwnAvatar(avatar!)
        }
        
        if name != nil {
            let command = Actor.editMyNameCommandWithName(name!)
            AAExecutions.execute(command!, type: .Safe, ignore: [], successBlock: successBlock, failureBlock: failureBlock)
        }

    }
    
    // MARK: - 群组操作
    
    /**
     创建新的群组
     
     - parameter groupTitle:       群组名字
     - parameter avatar:           群组头像
     - parameter uids:             邀请人ID列表
     - parameter successBlock:     成功回调
     - parameter failureBlock:     失败回调
     */
    public func groupCommand(creatGroupTitle groupTitle: String!, avatar: UIImage?, uids: [jint], successBlock: ((gid: jint!) -> Void)?, failureBlock: ((val: Any?) -> Void)?) {
        
        //  NSArray -> IOSIntArray
        let res = IOSIntArray(length: UInt(uids.count))
        var index: UInt = 0
        for i in uids {
            res.replaceIntAtIndex(index, withInt: i)
            index += 1
        }

         // 建组基本信息
        let command = Actor.createGroupCommandWithTitle(groupTitle, withAvatar: nil, withUids: res)
        
        //  进行安全请求，并回调
        AAExecutions.execute(command!, type: .Safe, ignore: [], successBlock: { (val) -> Void in
            
            let gid = (val as! JavaLangInteger).intValue
            //  图片比较大，先创建群组，然后上传图片。防止由于网络原因失败。原SDK逻辑
            if avatar != nil {
                self.groupCommand(changeGroupGid: gid, title: nil, avatar: avatar)
            }
            
            successBlock?(gid: gid)
            
            }, failureBlock: failureBlock)
    }
    
    /**
     更改群组名称、头像
     
     - parameter title:  群组名称
     - parameter gid:    群组ID
     - parameter avatar: 群组头像
     */
    public func groupCommand(changeGroupGid gid: jint!, title: String?, avatar: UIImage?) {
        if title != nil {
            Actor.editGroupTitleCommandWithGid(gid, withTitle: title)
        }
        if avatar != nil {
            Actor.changeGroupAvatar(gid, image: avatar!)
        }
    }
    
    /**
     离开群组
     
     - parameter gid:          群组ID
     - parameter successBlock: 成功回调
     - parameter failureBlock: 失败回调
     */
    public func groupCommand(leaveGid gid: jint!, successBlock: ((val: Any?) -> Void)?, failureBlock: ((val: Any?) -> Void)?) {
        let command = Actor.leaveGroupCommandWithGid(gid)
        AAExecutions.execute(command!, type: .Safe, ignore: [], successBlock: successBlock, failureBlock: failureBlock)
    }
}
